// Copyright 2008 Senary
// See credits.txt for details.

// This file is part of Omega VII.

// Omega VII is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Omega VII is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Omega VII.  If not, see <http://www.gnu.org/licenses/>.

#include <set>
#include <map>
#include "GameManager.h"
#include "InputManager.h"
#include "SpaceShip.h"
#include "MediaManager.h"
#include "Camera.h"

using namespace std;

InputManager::InputManager(void) : _isMousePressed(false)
{
	MediaManager* mm = MediaManager::getInstance();
	affirmative = mm->getSound("Affirmative.ogg");
	gogogo = mm->getSound("goGoGo.ogg");
	notagain = mm->getSound("notAgain.ogg");
	showtime = mm->getSound("itsShowTime.ogg");
}

InputManager::~InputManager(void)
{
}

void InputManager::mousePressed(var code)
{
	//haiz... need to travel that long to get back to myself :(
	GameManager::getInstance()->getInputManager()->onMousePressed(code);
}

// handler for mouse clicks

void InputManager::onMousePressed(var code)
{
	GameManager* gm = GameManager::getInstance();
	//coord of mouse click, in pixel
	pair<int, int>clickedPosition = make_pair(_INT(gm->ev->cursor->x), _INT(gm->ev->cursor->y)); 

	if (code == _VAR(280)) {
		// left mouse button
		_isMousePressed = true;
		_mousePressPos = Vector(gm->ev->cursor);

		//loop through all buttons to determine if button is clicked
		for(std::vector<Button*>::iterator it=_buttons.begin();
				it<_buttons.end();
				it++) {
			//determine if clickedPosition is within button's body
			if((*it)->withinRange(clickedPosition)) {
				//invoke the clicked event
				(*it)->mouseClicked(clickedPosition);
				// reset the _mousePressPos so no selection takes place
				_mousePressPos = Vector();
				//only 1 button can be clicked at a time
				break;
			}		
		}
	} else if (code == _VAR(282)) {
		// middle mouse button
		SpaceObject * so = objectAtPos(Vector(gm->ev->cursor));
		if (so != 0) {
			gm->getCamera()->setTarget(so);
		}
	} else if (code == _VAR(281)) {
		// right mouse button
		SpaceObject * so = objectAtPos(Vector(gm->ev->cursor));
		if (so != 0) {
			bool soundPlayed = false;
			for ( set<SpaceObject*>::iterator i = gm->_selectedObjects.begin();
						i != gm->_selectedObjects.end();
						++i ) {
				Spaceship* ss = dynamic_cast<Spaceship*>(*i);
				// Only set targets for human ships
				if (ss != 0 && ss != so && ss->getOwner() == gm->_players[0]) {
					ss->setTarget(so);
					if (*(gm->ev->key_ctrl)) {
						ss->setTactic(TT_AGRESSIVE);
					} else {
						ss->setTactic(TT_PASSIVE);
					}
					// Attacking sound, but only one sound per command;
					if (!soundPlayed) {
						if(ss->getType()==ST_METHI)
						{						
							snd_play(affirmative,_VAR(1000),_VAR(0));
						}
						if(ss->getType()==ST_JONTH)
						{						
							snd_play(gogogo,_VAR(1000),_VAR(0));
						}
						if(ss->getType()==ST_YATAI_VIII)
						{						
							snd_play(notagain,_VAR(1000),_VAR(0));
						}
						if(ss->getType()==ST_CYSUS)
						{						
							snd_play(showtime,_VAR(1000),_VAR(0));
						}
						soundPlayed = true;
					}

				}
			}
		}
	}
}

// handler for mouse clicks
void InputManager::onMouseReleased()
{
	GameManager* gm = GameManager::getInstance();
	
	if (_mousePressPos != Vector()) {
		// Left mouse button has been dragged.
		// Select all entities inside the rectangle.
		gm->_selectedObjects.clear();

		Vector mouseReleasePos(gm->ev->cursor);
		Vector topLeft(min(_mousePressPos.x, mouseReleasePos.x),
			min(_mousePressPos.y, mouseReleasePos.y), 0.0);
		Vector bottomRight(max(_mousePressPos.x, mouseReleasePos.x),
			max(_mousePressPos.y, mouseReleasePos.y), 0.0);

		// is it a single click or rectangle?
		if ((_mousePressPos - mouseReleasePos).r2() < 5.0) {
			// single click
			SpaceObject * so =  objectAtPos(mouseReleasePos);
			if (so != 0) {
				//Omega7 cannot be selected
				Planet* p = dynamic_cast<Planet*>(so);
				if (!(p != 0 && p->maxPopulation() == -1)) {
					// this is not omega7
					gm->addSelectedObject(so);
				}
			}
		} else {
			//rectangle
			for(map<SpaceObject*, ENTITY*>::iterator i = gm->_spaceObjectMap.begin();
				i != gm->_spaceObjectMap.end(); ++i) {
				VECTOR entPos;
				VECTOR * screenPos;
				i->first->getPosition().toGamestudio(&entPos);
				screenPos = vec_to_screen(&entPos, gm->ev->camera);
				if (screenPos != 0) {
					if (screenPos->x >= _VAR(topLeft.x) &&
						screenPos->x <= _VAR(bottomRight.x) &&
						screenPos->y >= _VAR(topLeft.y) &&
						screenPos->y <= _VAR(bottomRight.y)) {
							//prevent omega7 from being selected
							Planet* p = dynamic_cast<Planet*>(i->first);
							if (!(p != 0 && p->maxPopulation() == -1)) {
								// this is not omega7
								gm->addSelectedObject(i->first);
							}
					}
				}
			}
		}

	}

	// reset _mousePressPoint
	_mousePressPos = Vector();
}

//given (x,y) coord, return the spaceobject in the space world
SpaceObject* InputManager::objectAtPos(Vector const& pos) const
{
	GameManager* gm = GameManager::getInstance();
	
	VECTOR from;
	VECTOR to;
	gm->_pCamera->getPosition().toGamestudio(&from);
	pos.toGamestudio(&to);
	to.z = _VAR(1000000);
	vec_for_screen(&to, gm->ev->camera);
	if (c_trace(&from, &to, 0) != 0) {
		if (gm->ev->you != 0) {
			SpaceObject * so =  gm->findObject(gm->ev->you);
			return so;
		}
	}

	return 0;
}

void InputManager::initEventHandling(void)
{
	GameManager* gm = GameManager::getInstance();
	
	// mouse
	*(gm->ev->enable_mouse) = _VAR(1);
	*(gm->ev->mouse_mode) = _VAR(2); // mouse visible, mouse_force auto-calculated
	*(gm->ev->mouse_pointer) = _VAR(2); // arrow
	(gm->ev->mouse_map) = MediaManager::getInstance()->getImage("mouse_map.png");
	*(gm->ev->on_mouse_left) = (EVENT)(InputManager::mousePressed);
	*(gm->ev->on_mouse_middle) = (EVENT)(InputManager::mousePressed);
	*(gm->ev->on_mouse_right) = (EVENT)(InputManager::mousePressed);
}

void InputManager::update(float timestep, float totalTime)
{
	GameManager* gm = GameManager::getInstance();

	// Update the mouse pointer coordinates
	gm->ev->mouse_pos->x = gm->ev->cursor->x;
	gm->ev->mouse_pos->y = gm->ev->cursor->y;

	// detect mouse releases
	if (_isMousePressed && *(gm->ev->mouse_left) == 0) {
		_isMousePressed = false;
		onMouseReleased();
	}

	showToolTipText();
	updateCamera(timestep, totalTime);

	// draw the selection rectangle
	if (_mousePressPos != Vector() && *(gm->ev->mouse_left)) {
		gm->drawRect(_mousePressPos, Vector(gm->ev->cursor), Vector(0, 255, 0));
	}

}

// adds a button to the button vector
void InputManager::registerButton(Button* b)
{
	_buttons.push_back(b);
}

//update camera position when mouse pointer near screen edge
void InputManager::updateCamera(float timestep, float totalTime) 
{
	int up=0, down=0, left=0, right=0;
	GameManager* gm = GameManager::getInstance();

	if(gm->ev->cursor->x < _VAR(20))
		left = 1;
	if(gm->ev->cursor->x > gm->ev->screen_size->x - _VAR(20))
		right = 1;
	if(gm->ev->cursor->y < _VAR(20))
		up = 1;
	if(gm->ev->cursor->y > gm->ev->screen_size->y - _VAR(20))
		down = 1;

	gm->getCamera()->move(up, right, down, left, timestep);
}

void InputManager::showToolTipText()
{
	GameManager* gm = GameManager::getInstance();
	
	//make sure mouse is unclicked
	if(*(gm->ev->mouse_left) + 
			*(gm->ev->mouse_right) + 
			*(gm->ev->mouse_middle) != 0)
		return;
	
	pair<int, int>mousePos = make_pair(_INT(gm->ev->cursor->x), _INT(gm->ev->cursor->y)); 

	//loop through all buttons to determine if cursor is hovering over button
	for(std::vector<Button*>::iterator it=_buttons.begin();
			it<_buttons.end();
			it++) {
		//determine if the mouse position is within button's body
		if((*it)->withinRange(mousePos)) {
			//draw tool tip text
			draw_text(const_cast<char*>((*it)->getToolTipText().c_str()), 
					_VAR(mousePos.first) + _VAR(5), //x coord
					_VAR(mousePos.second) + _VAR(20), //y coord
					::vector(_VAR(0),_VAR(255),_VAR(255))); //yellow color
			//only 1 button can be hovered at a time
			break;
		}		
	}
}